﻿using System;
using System.IO;
using System.Web;
using System.Collections.Generic;
using System.Reflection;

namespace SimpleService.Database
{
    /// <summary>
    /// 載入provider.dll
    /// </summary>
    public class DbLoader
    {

        /// <summary>
        /// 取得目錄中,所有db類型
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, Type> GetDbTypes()
        {
            Dictionary<string, Type> allDbType = new Dictionary<string, Type>();
            List<string> paths = DbLoader.GetDbDll();
            foreach (string filePath in paths)
            {
                Assembly asm = Assembly.LoadFile(filePath);
                foreach (Type tempType in asm.GetExportedTypes())
                {
                    allDbType.Add(tempType.FullName, tempType);
                }  
            }
            return allDbType;
        }


        /// <summary>
        /// 尋找.dll並取得路徑
        /// </summary>
        /// <returns>所有.dll的路徑</returns>
        public static List<string> GetDbDll()
        {
            List<string> fileList = GetFileList("DbProvider", "dll");
            fileList = DeleteInvalid(fileList);
            return fileList;
        }


        /// <summary>
        /// 移除無效的路徑
        /// </summary>
        /// <param name="Paths">原路徑列表</param>
        /// <returns>有效的路徑列表</returns>
        private static List<string> DeleteInvalid(List<string> Paths)
        {
            string interfaceName = typeof(IDbProvider).FullName;
            List<string> RightPaths = new List<string>();
            foreach (string filePath in Paths)
            {
                Assembly asm = Assembly.LoadFile(filePath);
                foreach (Type tempType in asm.GetExportedTypes())
                {
                    IDbProvider dbProvider = LoadObject(asm, tempType.FullName, interfaceName) as IDbProvider;
                    if (dbProvider != null)
                    {
                        RightPaths.Add(filePath);
                        break;
                    }
                }

            }
            return RightPaths;
        }


        /// <summary>
        /// 載入object
        /// </summary>
        /// <param name="asm">組件</param>
        /// <param name="className">類別名</param>
        /// <param name="interfaceName">實作的介面名</param>
        /// <returns></returns>
        private static object LoadObject(Assembly asm, string className, string interfaceName)
        {
            Type classType = asm.GetType(className);
            bool checkInterface = CheckInterface(classType, interfaceName);
            if (checkInterface)
            {
                object o = (IDbProvider)Activator.CreateInstance(classType);
                return o;
            }
            else
            {
                return null;
            }
        }


        /// <summary>
        /// 檢查 是否有實現指定的Interface
        /// </summary>
        /// <param name="classType"></param>
        /// <param name="interfaceName"></param>
        /// <returns></returns>
        private static bool CheckInterface(Type classType, string interfaceName)
        {
            if (classType != null //不是空
                 && classType.IsClass //是class
                 && classType.IsPublic //是Public
                 && !classType.IsAbstract //不是抽像類別
                 && classType.GetInterface(interfaceName) != null) //有實現指定的Interface
            {
                return true;
            }
            else
            {
                return false;
            }
        }


        /// <summary>
        /// 取得[特定目錄]中[特定附檔名]的列表
        /// </summary>
        /// <param name="directory">目錄名稱</param>
        /// <param name="extensions">附檔名</param>
        /// <returns>路徑列表</returns>
        public static List<string> GetFileList(string directory, string extensions)
        {
            List<string> paths = new List<string>();
            try
            {
                string path = DbUtility.GetPath(directory);
                foreach (string filePath in Directory.GetFiles(path, "*." + extensions))
                {
                    paths.Add(filePath);
                }
            }
            catch (Exception exp)
            {
                throw exp;
            }
            return paths;
        }
    }
}
